home *** CD-ROM | disk | FTP | other *** search
/ AmigActive 10 / AACD 10.iso / AACD / Magazine / Online / httpproxy / src / httpdelete.c < prev    next >
C/C++ Source or Header  |  1996-08-20  |  17KB  |  613 lines

  1. /*(( "Header" */
  2. /*
  3.  * $Id: httpdelete.c,v 1.5 1996/08/12 03:33:36 mshopf Exp mshopf $
  4.  *
  5.  * (c) 1995-96 Matthias Hopf
  6.  *
  7.  * Invald File Deleter for httpproxy.
  8.  *
  9.  * This utility recursively deletes all invalid cache files and
  10.  * directory structures.
  11.  * When httpproxy is running it will inform it about cache file removals.
  12.  * (not yet implemented and no more needed).
  13.  */
  14.  
  15. /*
  16.  * $Log: httpdelete.c,v $
  17.  * Revision 1.5  1996/08/12  03:33:36  mshopf
  18.  * deleting strange (7) files.
  19.  *
  20.  * Revision 1.4  1996/08/11  22:25:15  mshopf
  21.  * reworked debug messages.
  22.  *
  23.  * Revision 1.3  1996/07/17  16:42:42  mshopf
  24.  * support for new cache system.
  25.  *
  26.  * Revision 1.2  1996/04/26  05:18:25  mshopf
  27.  * logfile format, option priority.
  28.  * V0.13 alpha 5 fix.
  29.  *
  30.  * Revision 1.1  1996/04/16  04:39:29  mshopf
  31.  * Initial revision
  32.  *
  33.  */
  34.  
  35.  
  36. /*)) */
  37. /*(( "Logfile Format" */
  38.  
  39. /* Format of the log file: */
  40.  
  41. /*
  42.  * LogFile         ::= { LogEntry '\n' }*
  43.  * LogEntry        ::= File | Directory | Error | Warn | Special
  44.  * Special         ::= '*' DescriptiveText
  45.  * Error           ::= '#' DescriptiveText
  46.  * Warn            ::= '+' DescriptiveText
  47.  * File            ::= ' ' Name
  48.  * Directory       ::= ' ' Name ' (dir)'
  49.  * Name            ::= { alphanummeric | '@' | '_' }*
  50.  * DescriptiveText ::= { printable | ' ' }*
  51.  */
  52. /*)) */
  53. /*(( "Includes & Konstanten" */
  54.  
  55. #include <stdio.h>
  56. #include <stdlib.h>
  57. #include <errno.h>
  58. #include <string.h>
  59.  
  60. #include <exec/exec.h>
  61. #include <dos.h>
  62. #include <dos/exall.h>
  63. #include <dos/datetime.h>
  64.  
  65. #include <proto/exec.h>
  66. #include <proto/dos.h>
  67.  
  68. #include "httpproxy.h"
  69. #include "cache.h"
  70.  
  71. #define MAX_DEPTH 20                 /* Maximum recursion depth +1 (note that WorkData[0] is reserved) */
  72. #define DEFAULT_EXALLBUFSIZE 2048    /* default number of ExAll() examination buffer bytes per recursion
  73.                       * (may be less as additional info is stored here) */
  74. #define DEFAULT_DELETETIME (60*24*60*60) /* default deletetime in seconds (two months here) */
  75. #define MAX_DIRNAME 1024             /* Maximum Size of directory name */
  76.  
  77.                      /* The following macro is only here for historical reasons. It is not used anymore */
  78.                      /* Note: this macro won't handle files older than aprox. 136 years correctly :-P */
  79. /*
  80. #define difftime(x,y) ((((long)(x)->ds_Days   - (long)(y)->ds_Days)    * 24L * 60L +      \
  81.             ((long)(x)->ds_Minute - (long)(y)->ds_Minute)) * 60L +     \
  82.             ((long)(x)->ds_Tick    - (long)(y)->ds_Tick)    / TICKS_PER_SECOND )
  83.  */
  84.  
  85. /*)) */
  86. /*(( "Global Variables" */
  87.  
  88. typedef struct {
  89.            BPTR                DirLock;
  90.            short               More;
  91.            short               Needed;  /* directory is needed, e.g. not empty */
  92.            struct ExAllControl *ExAllCtrl;
  93.            struct ExAllData    *Buffer;
  94.            struct ExAllData    *CurrentBuf;
  95.            } work_t;
  96.  
  97. long   __oslibversion = 37;
  98. #ifdef DEBUG
  99. int DebugLevel = -1;
  100. #endif
  101.  
  102. char   *LogName     = NULL;
  103. FILE   *LogStream   = NULL;
  104. BPTR   CacheDirLock = NULL;
  105.  
  106. work_t WorkData     [MAX_DEPTH];        /* Note: C ansi standard initializes this with NULL */
  107.                     /* WorkData[0].DirLock is reserved for the initial working directory */
  108.  
  109. char   StringDay    [LEN_DATSTRING];
  110. char   StringTime   [LEN_DATSTRING];
  111. char   StringDate   [LEN_DATSTRING];
  112. struct DateTime CurrentDT = { {0, 0, 0}, FORMAT_DOS, 0, StringDay, StringDate, StringTime };
  113. struct DateStamp ValidDS;
  114.  
  115. int    DeleteTime   = DEFAULT_DELETETIME;
  116. ULONG  ExAllBufSize = DEFAULT_EXALLBUFSIZE;
  117. int    CheckOnly    = 0;
  118. long   DelayTicks   = 0;
  119.  
  120. /*)) */
  121.  
  122. /*(( "ExitAll (), Error ()" */
  123.  
  124. /* Close everything and return */
  125.  
  126. void ExitAll (int Ret)
  127. {
  128.     work_t *W;
  129.     if (WorkData->DirLock)
  130.     CurrentDir (WorkData->DirLock);
  131.     for (W = & WorkData [1]; W < & WorkData [MAX_DEPTH]; W++)
  132.     {
  133.     if (W->ExAllCtrl)
  134.         FreeDosObject (DOS_EXALLCONTROL, W->ExAllCtrl);
  135.     W->ExAllCtrl = NULL;                 /* not needed as we exit immedeately */
  136.     if (W->DirLock)
  137.         UnLock (W->DirLock);
  138.     W->DirLock = NULL;                   /* but let's keep it consistent... */
  139.     if (W->Buffer)
  140.         FreeMem (W->Buffer, ExAllBufSize);
  141.     W->Buffer = NULL;
  142.     }
  143.     if (LogStream)
  144.     fclose (LogStream);
  145.     LogStream = NULL;
  146.     UnLock (CacheDirLock);                   /* may be already NULL */
  147.     CacheDirLock = NULL;
  148.     exit (Ret);
  149. }
  150.  
  151.  
  152. /* Print out error message and exit() */
  153.  
  154. void Error (char *Msg)
  155. {
  156.     if (LogStream)
  157.     fprintf (LogStream, "# Error: %s\n", Msg);
  158.     fprintf (stderr, "Error: %s\n", Msg);
  159.     ExitAll (10);
  160. }
  161.  
  162. /*)) */
  163. /*(( "Init ()" */
  164.  
  165. /* Init all global variables, open logfile if any */
  166.  
  167. void Init (char *ProgName, char *LogName)
  168. {
  169.     long CalcTime;
  170.  
  171.     if (LogName)
  172.     {
  173.     if (! (LogStream = fopen (LogName, "w+")))
  174.         Error ("can't open logfile");
  175.     }
  176.  
  177.     DateStamp (&CurrentDT.dat_Stamp);
  178.     DateToStr (&CurrentDT);
  179.     if (LogStream)
  180.     fprintf (LogStream, "* %s startup on %s, %s %s\n", ProgName, StringDay, StringDate, StringTime);
  181.  
  182.     /* Could use the DateStamp entries, but I don't wanna rely on the entries being signed */
  183.     CalcTime         = CurrentDT.dat_Stamp.ds_Tick - (DeleteTime % 60) * TICKS_PER_SECOND;
  184.     if (CalcTime < 0)
  185.     {
  186.     ValidDS.ds_Tick = CalcTime + 60 * TICKS_PER_SECOND;
  187.     CalcTime = -1;
  188.     }
  189.     else
  190.     {
  191.     ValidDS.ds_Tick = CalcTime;
  192.     CalcTime = 0;
  193.     }
  194.     CalcTime        += CurrentDT.dat_Stamp.ds_Minute - (DeleteTime / 60) % (24 * 60);
  195.     if (CalcTime < 0)
  196.     {
  197.     ValidDS.ds_Minute = CalcTime + 24 * 60;
  198.     CalcTime = -1;
  199.     }
  200.     else
  201.     {
  202.     ValidDS.ds_Minute = CalcTime;
  203.     CalcTime = 0;
  204.     }
  205.     CalcTime        += CurrentDT.dat_Stamp.ds_Days - DeleteTime / (24 * 60 * 60);
  206.     if (CalcTime < 0)                              /* kidding?!? */
  207.     Error ("invald time range");
  208.     ValidDS.ds_Days = CalcTime;
  209. }
  210.  
  211. /*)) */
  212. /*(( "ParseOpt ()" */
  213.  
  214. /* Parse options template */
  215. /* <- CacheDirLock ggf. Lock auf CacheDir */
  216.  
  217. void ParseOpt (char *PrgName)
  218. {
  219.     char *Template  = "CACHEDIR=DIR/A,TIME/N,LOGFILE=LOG/K,EXBUFFERSIZE=EXBUF/K/N,CHECKONLY=CHECK/S,DELAY/K/N,PRIORITY=PRI/K/N";
  220.     long RetArray[] = { 0, 0, 0, 0, 0, 0, 0 };
  221.     struct RDArgs *Args;
  222.  
  223.     if (! (Args = ReadArgs (Template, RetArray, NULL)))
  224.     {
  225.     fprintf (stderr, "%s\n"
  226.          "\tTIME:         Spezifies minimum age in seconds before a file is removed.\n"
  227.          "\t              Defaults to %d seconds.\n"
  228.          "\tCACHEDIR:     Location of cache files to be scanned.\n"
  229.          "\tLOGFILE:      Name of the logfile (none when omitted).\n"
  230.          "\tEXBUFFERSIZE: Size of the examination buffer (minimum is about 64 bytes).\n"
  231.          "\t              Defaults to %d bytes.\n"
  232.          "\tCHECKONLY:    Do not perform deletes, only write log entries.\n"
  233.          "\tDELAY:        For use in server environments. Specifies the number of ticks\n"
  234.          "\t              to be waited after each ExAll() call. Mostly usefull with not\n"
  235.          "\t              too high values for EXBUFFERSIZE (use the default).\n"
  236.          "\tPRIORITY:     Priority while running. The current priority won't be\n"
  237.          "\t              changed when this option is not specified.\n"
  238.          "Check the docs for more information about httpproxy and its utilities.\n",
  239.          Template, DEFAULT_DELETETIME, DEFAULT_EXALLBUFSIZE);
  240.     ExitAll (10);
  241.     }
  242.  
  243.     if (! (CacheDirLock = Lock ((char *) RetArray [0], ACCESS_READ))) /* CACHEDIR */
  244.     {
  245.     FreeArgs (Args);
  246.     Error ("can't lock cache directory");
  247.     }
  248.     if (RetArray [1])                                 /* TIME */
  249.     DeleteTime   = * (long *) RetArray [1];
  250.     LogName      = (char *)   RetArray [2];           /* LOGFILE */
  251.     if (RetArray [3])                                 /* EXBUFFERSIZE */
  252.     ExAllBufSize = * (long *) RetArray[3];
  253.     CheckOnly    = RetArray [4];                      /* CHECKONLY */
  254.     if (RetArray [5])                                 /* DELAY */
  255.     DelayTicks = * (long *) RetArray [5];
  256.     if (RetArray [6])                                 /* PRIORITY */
  257.     SetTaskPri (FindTask (NULL), * (long *) RetArray [6]);
  258.  
  259.     Init (PrgName, LogName);
  260.  
  261.     FreeArgs (Args);
  262. }
  263.  
  264. /*)) */
  265. /*(( "GenerateDirName ()" */
  266.  
  267. /* Generate current workdir name into static buffer */
  268.  
  269. char *GenerateDirName (work_t *Working)
  270. {
  271.     static char   Name [MAX_DIRNAME];
  272.     char   *N = Name;
  273.     work_t *W;
  274.  
  275.     for (W = & WorkData [1]; W < Working; W++)        /* Working is the current working directory */
  276.     {
  277.     strcpy (N, W->CurrentBuf->ed_Name);
  278.     N   += strlen (N);
  279.     *N++ = '/';
  280.     }
  281.     *N = '\0';
  282.     return (Name);
  283. }
  284.  
  285. /*)) */
  286. /*(( "EnterDir ()" */
  287.  
  288. /* Shall we enter a named directory? */
  289.  
  290. int EnterDir (struct ExAllData *E)
  291. {
  292.     if (CacheRemoveDir (E->ed_Name, FALSE) != 1)
  293.     return FALSE;                    /* skip special dirs */
  294.     return TRUE;
  295. }
  296.  
  297. /*)) */
  298. /*(( "FileValid ()" */
  299.  
  300. /* Check whether this is a valid cache entry file */
  301.  
  302. int FileValid (work_t *W, struct ExAllData *E)
  303. {
  304.     if (CompareDates ((struct DateStamp *) & E->ed_Days, & ValidDS) <= 0)
  305.     return TRUE;
  306.     else
  307.     return FALSE;
  308. }
  309.  
  310. /*)) */
  311. /*(( "CheckFile ()" */
  312.  
  313. void CheckFile (work_t *W, struct ExAllData *E)
  314. {
  315.     /* check type of cache file */
  316.     switch (CacheRemove (E->ed_Name, FALSE)) {
  317.     case 1:                          /* - standard file: check it */
  318.     if (FileValid (W, E))
  319.     {
  320.         W->Needed = TRUE;
  321.         return;
  322.     }
  323.     break;
  324.  
  325.     case 2:                          /* directory management file */
  326.     case 4:                          /* no more existant */
  327.     case 5:                          /* cache related file */
  328.     return;                      /* ->nothing to do */
  329.  
  330.     case 7:                          /* strange files to be deleted */
  331.     if (LogStream)
  332.         fprintf (LogStream, "+ file '%s%s' lost info file - deleting\n", GenerateDirName (W), E->ed_Name);
  333.     break;
  334.  
  335.     case 3:                          /* stange file */
  336.     if (LogStream)
  337.         fprintf (LogStream, "# file '%s%s' is strange - skipping\n",
  338.              GenerateDirName (W), E->ed_Name);
  339.     W->Needed = TRUE;            /* the dir is 'valid' as we may *not* remove it */
  340.     return;
  341.  
  342.     case 6:                          /* special file */
  343.     W->Needed = TRUE;
  344.     return;                      /* not handled by httpdelete */
  345.  
  346.     case 0:                          /* we *don't* do deletes here! */
  347.     default:
  348.     assert (0);
  349.     }
  350.  
  351.     /* File is not valid, so it must be removed! */
  352.     if (CheckOnly)
  353.     {
  354.     if (LogStream)
  355.         fprintf (LogStream, " %s%s\n", GenerateDirName (W), E->ed_Name);
  356.     }
  357.     else
  358.     {
  359.     switch (CacheRemove (E->ed_Name, TRUE)) {
  360.     case 1:                            /* success: deleted file */
  361.         if (LogStream)
  362.         fprintf (LogStream, " %s%s\n", GenerateDirName (W), E->ed_Name);
  363.         break;
  364.  
  365.     case 4:                            /* no more existing... */
  366.         break;
  367.     case 0:                            /* delete error */
  368.         if (LogStream)
  369.         {
  370.         char ErrMsg [128];
  371.  
  372.         Fault (IoErr (), "", ErrMsg, 128);
  373.         fprintf (LogStream, "# file '%s%s' delete error: %s\n",
  374.              GenerateDirName (W), E->ed_Name, ErrMsg);
  375.         }
  376.         W->Needed = TRUE;
  377.         break;
  378.  
  379.     default:                           /* all other cases should *not* get here... */
  380.         assert (0);
  381.     }
  382.     }
  383. }
  384.  
  385. /*)) */
  386. /*(( "CheckDir ()" */
  387.  
  388. /* Check directory for deleting it */
  389.  
  390. void CheckDir (work_t *Parent, struct ExAllData *E, int Needed)
  391. {
  392.     if (Needed)
  393.     return;
  394.     else if (CheckOnly)
  395.     {
  396.     if (LogStream)
  397.         fprintf (LogStream, " %s%s (dir)\n", GenerateDirName (Parent), E->ed_Name);
  398.     }
  399.     else
  400.     {
  401.     switch (CacheRemoveDir (E->ed_Name, TRUE)) {
  402.     case 1:
  403.         if (LogStream)
  404.         fprintf (LogStream, " %s%s (dir)\n", GenerateDirName (Parent), E->ed_Name);
  405.         break;
  406.  
  407.     case 0:
  408.         Parent->Needed = TRUE;          /* We won't be able to delete the directory */
  409.         if (LogStream)
  410.         {
  411.         char ErrMsg [128];
  412.  
  413.         Fault (IoErr (), "", ErrMsg, 128);
  414.         fprintf (LogStream, "# directory '%s%s' delete error: %s\n",
  415.              GenerateDirName (Parent), E->ed_Name, ErrMsg);
  416.         }
  417.         break;
  418.  
  419.     case 2:
  420.         Parent->Needed = TRUE;          /* We won't be able to delete the directory */
  421.         break;
  422.  
  423.     default:                            /* special dirs should not be entered and thus not deleted! */
  424.         assert (0);
  425.     }
  426.     }
  427. }
  428.  
  429. /*)) */
  430. /*(( "DeleteLoop ()" */
  431.  
  432. /* Major Loop: Nonrekursive rekursive loop through a directory */
  433. /* <- BeginLock will be freed! */
  434.  
  435. void DeleteLoop (BPTR BeginLock)
  436. {
  437.     work_t *W = & WorkData [1];
  438.     struct ExAllData *E;
  439.  
  440.     WorkData->CurrentBuf = NULL;
  441.     WorkData->DirLock    = CurrentDir (BeginLock);
  442.  
  443.     W->DirLock    = BeginLock;
  444.     W->CurrentBuf = NULL;           /* For subsequent calls */
  445.     W->More       = FALSE;
  446.     W->Needed     = TRUE;           /* Don't delete main directory (wouldn't be needed due to special directories) */
  447.  
  448.     while (W > WorkData)            /* W[0] is reserved for the initial directory */
  449.     {
  450.     do
  451.     {
  452.         /* Main Outer Loop */
  453.  
  454.         /* Check for Ctrl-C once a while (not every time...) */
  455.         if (SetSignal (0L, SIGBREAKF_CTRL_C) & SIGBREAKF_CTRL_C)
  456.         Error ("interrupted");
  457.         if (DelayTicks)
  458.         Delay (DelayTicks);
  459.  
  460.         /* Allocate all necessary things */
  461.         if (! W->Buffer)
  462.         if (! (W->Buffer = AllocMem (ExAllBufSize, 0L)))
  463.         {
  464.             if (LogStream)
  465.             fprintf (LogStream, "Not enough memory - skipping");
  466.             break;
  467.         }
  468.         if (! W->ExAllCtrl)
  469.         {
  470.         if (! (W->ExAllCtrl = (struct ExAllControl *) AllocDosObject(DOS_EXALLCONTROL,NULL)))
  471.         {
  472.             if (LogStream)
  473.             fprintf (LogStream, "# can't alloc dosobject - skipping\n");
  474.             break;
  475.         }
  476.         W->ExAllCtrl->eac_LastKey = 0;
  477.         W->CurrentBuf = NULL;
  478.         }
  479.  
  480.         /* Examine directory when needed */
  481.         if (W->CurrentBuf)                         /* Continue aborted directory */
  482.         E = W->CurrentBuf->ed_Next;
  483.         else                                       /* start new examination */
  484.         {
  485.         W->More = ExAll (W->DirLock, W->Buffer, ExAllBufSize, ED_DATE, W->ExAllCtrl);
  486.         if ((! W->More) && (IoErr () != ERROR_NO_MORE_ENTRIES))
  487.         {
  488.             if (LogStream)
  489.             fprintf (LogStream, "# ExAll() Error: %d - skipping\n", IoErr());
  490.             FreeDosObject (DOS_EXALLCONTROL, W->ExAllCtrl);         /* Remove eventually corrupt DosObject */
  491.             W->ExAllCtrl = NULL;                                    /* (ExAllEnd is V39 only) */
  492.             break;
  493.         }
  494.         if (! W->ExAllCtrl->eac_Entries)
  495.             /* ExAll failed normally with no entries */
  496.             continue;                   /* ("More" is *usually* zero) */
  497.         E = W->Buffer;
  498.         }
  499.  
  500.         W->CurrentBuf = NULL;
  501.         while (E)
  502.         {
  503.             /* Main Inner Loop */
  504.         if (E->ed_Type > 0)           /* it is a directory */
  505.         {
  506.             if (! EnterDir (E))
  507.             W->Needed = TRUE;     /* don't delete non-entered directories */
  508.             else
  509.             {
  510.             if (W >= & WorkData [MAX_DEPTH-1])
  511.             {
  512.                 if (LogStream)
  513.                 fprintf (LogStream, "# maximum depth reached, skipping\n");
  514.             }
  515.             else
  516.             {
  517.                 /* Enter next directory level */
  518.                 W->CurrentBuf = E;
  519.                 W++;
  520.                 W->CurrentBuf = NULL;
  521.                 W->More       = TRUE;
  522.                 W->Needed     = FALSE;
  523.                 W->DirLock    = Lock (E->ed_Name, ACCESS_READ);
  524.                 CurrentDir (W->DirLock);          /* in case it is 0, we're temporary on sys: */
  525.                 if (! W->DirLock)
  526.                 W->More  = FALSE;
  527.                 break;
  528.             }
  529.             }
  530.         }
  531.         else
  532.             CheckFile (W, E);
  533.  
  534.         E = E->ed_Next;
  535.         }
  536.  
  537.     } while (W->More);
  538.  
  539.     if (W->ExAllCtrl)
  540.         W->ExAllCtrl->eac_LastKey = 0;          /* for subsequent uses */
  541.         /* ExAllCtrl is not deallocated for speedup in subsequent uses */
  542.  
  543.         /* go to higher directory level */
  544.     W--;
  545.     CurrentDir (W->DirLock);
  546.     UnLock (W [1] .DirLock);
  547.     W [1] .DirLock = NULL;
  548.     if (W [1] .Needed)
  549.         W->Needed = TRUE;
  550.  
  551.         /* check directory (W is the parent directory) */
  552.     if (W->CurrentBuf)
  553.         CheckDir (W, W->CurrentBuf, W [1] .Needed);
  554.     }
  555. }
  556.  
  557. /*)) */
  558. /*(( "main ()" */
  559.  
  560. /* The main routine */
  561.  
  562. void main (int argc, char **argv)
  563. {
  564.     BPTR LastDir, TestLock;
  565.  
  566.     ParseOpt (argv [0]);
  567.  
  568.     /* Test existance of CACHEDIRVALIDFILE */
  569.     LastDir  = CurrentDir (CacheDirLock);
  570.     TestLock = Lock (CACHEDIRVALIDFILE, ACCESS_READ);
  571.     CurrentDir (LastDir);
  572.     if (! TestLock)
  573.     Error ("can't lock '" CACHEDIRVALIDFILE "' - seems to be the wrong directory!");
  574.     UnLock (TestLock);
  575.  
  576.     TestLock     = CacheDirLock;
  577.     CacheDirLock = NULL;                        /* CacheDirLock is unlocked by DeleteLoop */
  578.     DeleteLoop (TestLock);
  579.  
  580.     ExitAll (0);
  581. }
  582. /*)) */
  583.  
  584. /*(( "assert()" */
  585.  
  586. #ifndef NDEBUG
  587.  
  588. void ASSERT (int x, const char *text, const char *file, const char *func, int line)
  589. {
  590.     if (x)
  591.     return;
  592.     if (! text)
  593.     text = "unknown";
  594.     fprintf (stderr, "assertion (%s) failed in '%s' of '%s' on line %d\n", text, func, file, line);
  595.     ExitAll (20);
  596.     /*NOTREACHED*/
  597. }
  598.  
  599. #endif /* NDEBUG */
  600.  
  601. /*)) */
  602. /*(( "LogErr ()" */
  603.  
  604. /* We don't need LogErr -> dummy function */
  605.  
  606. void LogErr (request_t *Req, const char *Status, const char *Url, int ErrNo, const char *Reason, ...)
  607. {
  608.     ASSERT (0, Reason, __FILE__, __FUNC__, 0);
  609. }
  610.  
  611. /*)) */
  612.  
  613.